/*
 * sync_att.h
 *
 *  Created on: Sep 3, 2013
 *      Author: killerg
 */

#ifndef SYNC_ATT_H_
#define SYNC_ATT_H_

#include "share/cs_msg.pb.h"
#include "share/json/json.h"

using namespace std;
using namespace cs;


template<typename AttIndexT>
struct sa_traits_t {

};

template<>
struct sa_traits_t<EPlAtt8Save> {
    typedef int64_t AttValueT;

    enum {
        AttIndexNum = cs::EPlAtt8Save_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Pl8s,
        DefaultValue = 0,
    };

    static int64_t get(const Json::Value &json) {
        return json.asInt64();
    }

    static void append(int64_t value, Json::Value &json) {
        json.append(Json::Int64(value));
    }


    static void add_init(int64_t value, cs::OSyncAttInit* init) {
        init->add_n64(value);
    }
    static void add_sync(int32_t index, int64_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_n64(value);
    }
};

template<>
struct sa_traits_t<EPlAtt4Save> {
    typedef int32_t AttValueT;

    enum {
        AttIndexNum = cs::EPlAtt4Save_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Pl4s,
        DefaultValue = 0,
    };

    static int32_t get(const Json::Value &json) {
        return json.asInt();
    }

    static void append(int32_t value, Json::Value &json) {
        json.append(value);
    }

    static void add_init(int32_t value, cs::OSyncAttInit* init) {
        init->add_n32(value);
    }
    static void add_sync(int32_t index, int32_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_n32(value);
    }
};

template<>
struct sa_traits_t<EPlAttDSave> {
    typedef double_t AttValueT;

    enum {
        AttIndexNum = cs::EPlAttDSave_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Plds,
        DefaultValue = 0,
    };

    static double_t get(const Json::Value &json) {
        return json.asInt64();
    }

    static void append(double value, Json::Value &json) {
        json.append(value);
    }

    static void add_init(double_t value, cs::OSyncAttInit* init) {
        init->add_d(value);
    }
    static void add_sync(int32_t index, double_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_d(value);
    }
};
template<>
struct sa_traits_t<EPlAttSSave> {
    typedef string AttValueT;

    enum {
        AttIndexNum = cs::EPlAttSSave_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Plss,
        DefaultValue = 0,
    };

    static string get(const Json::Value &json) {
        return json.asString();
    }

    static void append(const string &value, Json::Value &json) {
        json.append(value);
    }

    static void add_init(const string &value, cs::OSyncAttInit* init) {
        init->add_str(value);
    }
    static void add_sync(int32_t index, const string &value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_str(value);
    }
};


template<>
struct sa_traits_t<EPeAtt8Save> {
    typedef int64_t AttValueT;

    enum {
        AttIndexNum = cs::EPeAtt8Save_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Pe8s,
        DefaultValue = 0,
    };

    static int64_t get(const Json::Value &json) {
        return json.asInt64();
    }

    static void append(int64_t value, Json::Value &json) {
        json.append(Json::Int64(value));
    }


    static void add_init(int64_t value, cs::OSyncAttInit* init) {
        init->add_n64(value);
    }
    static void add_sync(int32_t index, int64_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_n64(value);
    }
};

template<>
struct sa_traits_t<EPeAtt4Save> {
    typedef int32_t AttValueT;

    enum {
        AttIndexNum = cs::EPeAtt4Save_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Pe4s,
        DefaultValue = 0,
    };

    static int32_t get(const Json::Value &json) {
        return json.asInt();
    }

    static void append(int32_t value, Json::Value &json) {
        json.append(value);
    }

    static void add_init(int32_t value, cs::OSyncAttInit* init) {
        init->add_n32(value);
    }
    static void add_sync(int32_t index, int32_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_n32(value);
    }
};

template<>
struct sa_traits_t<EPeAttDSave> {
    typedef double_t AttValueT;

    enum {
        AttIndexNum = cs::EPeAttDSave_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Peds,
        DefaultValue = 0,
    };

    static double_t get(const Json::Value &json) {
        return json.asInt64();
    }

    static void append(double value, Json::Value &json) {
        json.append(value);
    }

    static void add_init(double_t value, cs::OSyncAttInit* init) {
        init->add_d(value);
    }
    static void add_sync(int32_t index, double_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_d(value);
    }
};
template<>
struct sa_traits_t<EPeAttSSave> {
    typedef string AttValueT;

    enum {
        AttIndexNum = cs::EPeAttSSave_ARRAYSIZE,
        Save = true,
        Sync = true,
        Type = ESAT_Pess,
        DefaultValue = 0,
    };

    static string get(const Json::Value &json) {
        return json.asString();
    }

    static void append(const string &value, Json::Value &json) {
        json.append(value);
    }

    static void add_init(const string &value, cs::OSyncAttInit* init) {
        init->add_str(value);
    }
    static void add_sync(int32_t index, const string &value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_str(value);
    }
};

template<>
struct sa_traits_t<EPlAtt8Nosave> {
    typedef int64_t AttValueT;

    enum {
        AttIndexNum = cs::EPlAtt8Nosave_ARRAYSIZE,
        Save = false,
        Sync = true,
        Type = ESAT_Pl8n,
        DefaultValue = -1,
    };

    static int64_t get(const Json::Value &json) {
        assert(0);
        return -1;
    }

    static void append(int64_t value, Json::Value &json) {
        assert(0);
    }

    static void add_init(int64_t value, cs::OSyncAttInit* init) {
        init->add_n64(value);
    }
    static void add_sync(int32_t index, int64_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_n64(value);
    }
};

template<>
struct sa_traits_t<EPlAtt4Nosave> {
    typedef int32_t AttValueT;

    enum {
        AttIndexNum = cs::EPlAtt4Nosave_ARRAYSIZE,
        Save = false,
        Sync = true,
        Type = ESAT_Pl4n,
        DefaultValue = -1,
    };

    static int32_t get(const Json::Value &json) {
        assert(0);
        return -1;
    }

    static void append(int32_t value, Json::Value &json) {
        assert(0);
    }

    static void add_init(int32_t value, cs::OSyncAttInit* init) {
        init->add_n32(value);
    }
    static void add_sync(int32_t index, int32_t value, cs::OSyncAtt* syncatt) {
         syncatt->set_index(index);
         syncatt->set_n32(value);
    }
};


struct player_t;
template<typename AttIndexT>
struct sync_att_t {
    typedef sa_traits_t<AttIndexT> traits;


    typename traits::AttValueT data[traits::AttIndexNum];
    std::bitset<traits::AttIndexNum> chged;

    sync_att_t() {
        for (int i=0; i<traits::AttIndexNum; ++i)
            data[i] = traits::DefaultValue;
    }

    typename traits::AttValueT get(AttIndexT index) {
        return data[index];
    }

    void set(AttIndexT index, typename traits::AttValueT value) {
        if (data[index] == value)
            return;

        data[index] = value;
        chged.set(index);
    }

    bool init(const sync_att_t<AttIndexT> &att) {
        for (int i=0; i<traits::AttIndexNum; ++i)
            data[i] = att.data[i];

        chged.reset();
        return true;
    }

    bool init(const Json::Value &json) {
        if (!traits::Save)
            return true;

        for (int i=0; i<traits::AttIndexNum; ++i)
            data[i] = traits::get(json.get(i, 0));

        chged.reset();
        return true;
    }

    void save(Json::Value &json) {
        if (!traits::Save)
            return;

        for (int i=0; i<traits::AttIndexNum; ++i)
            traits::append(data[i], json);
    }

    void fill_init(cs::OSyncAttInit* init) {
        init->set_type(cs::ESyncAttType(traits::Type));

        for (int i=0; i<traits::AttIndexNum; ++i)
            traits::add_init(data[i], init);

    }

    bool need_sync() {
        return traits::Sync && chged.any();
    }

    void fill_sync(cs::OSyncAttSync* attsync) {
        if (!need_sync())
            return;

        attsync->set_type(ESyncAttType(traits::Type));

        for (int i=0; i<traits::AttIndexNum; ++i) {
            if (!chged.test(i))
                continue;

            traits::add_sync(i, data[i], attsync->add_att());
        }

        chged.reset();
    }
};



#endif /* SYNC_ATT_H_ */
